import logging
import os
import urllib
import webapp2

from google.appengine.ext.webapp import template

from chat       import ROOM_URL_ARGUMENT, USER_URL_ARGUMENT
from model.user import User
from model.user import LIMITS as USER_LIMITS
from model.room import Room, NameNotUnique, RoomIsFull, UserAlreadyInRoom, \
                       NameInvalidFormat, NameInvalidLength
from model.room import LIMITS as ROOM_LIMITS



class LoginPage(webapp2.RequestHandler):
    """
    Page with a form to log into application.
    
    When rendernig a page, provides template dict errors with following kinds
    of errors (keys):
    - authentication_fail
    - room_name_not_available
    - room_name_invalid_format
    - room_name_invalid_length
    - room_not_exist
    - room_full
    - user_already_in_room
    
    """
    
    def get(self):
        """Page with an empty login form."""
        self.render_page()

    def post(self):
        """Authentication request."""
        
        username  = self.request.get("username")
        password  = self.request.get("password")
        room_type = self.request.get("room-type")
        room_name = self.request.get("room-name")
        logging.debug("Login authentication request for user %s with room type %s and room name %s" \
            % (username, room_type, room_name))
        # Used to re-render page on errors.
        template_values = {
            "username" : username,
            "room_type": self.request.get("room-type"),
            "room_name": room_name
        }
        
        user = User.all().filter("username", username).get()
        
        # Checking username and password.
        if (user is None) or (not user.check_password(password)):
            # User doesn't exist or password didn't match.
            logging.debug("Login authentication for user %s failed" \
                % username)
            self.render_page(template_values, { "authentication_fail": True })
            return

        # Room selection.
        if room_type == "new-room":
            try:
                # Creating a new room.
                Room.check_name_uniqueness(room_name)
                logging.info("Creating a new room %s" % room_name)
                room = Room(name=room_name)
            except NameNotUnique:   # Thrown by check_name_uniqueness().
                # There already is a room with that name.
                logging.debug("Cannot create a room %s, name already taken" % room_name)
                self.render_page(template_values, { "room_name_not_unique": True })
                return
            except NameInvalidFormat:   # Thrown by Room() constructor.
                logging.debug("Cannot create a room %s, name invalid format" % room_name)
                self.render_page(template_values, { "room_name_invalid_format": True })
                return
            except NameInvalidLength:   # Thrown by Room() constructor.
                logging.debug("Cannot create a room %s, name invalid length" % room_name)
                self.render_page(template_values, { "room_name_invalid_length": True })
                return
        elif room_type == "existing-room":
            room = Room.all().filter("name", room_name).filter("expired", False).get()
            if room:
                # Joining a room.
                logging.debug("Joining a room %s" % room_name)
            else:
                # Room with this name doesn't exist.
                logging.debug("Cannot join a room %s, no room with such name" % room_name)
                self.render_page(template_values, { "room_not_exist": True })
                return
        else:
            # Unknown room-type value
            logging.error("Login authentication request with unknown room-type value %s" % room_type)
            self.redirect(webapp2.uri_for("main"))
            return
        
        # Adding a user.
        try:
            logging.info("Adding user %s to room %s" % (user.username, room.name))
            room.add_user(user)
        except RoomIsFull:
            logging.debug("Cannot add user %s to room %s, room full" % (user.username, room.name))
            self.render_page(template_values, { "room_full": True })
            return
        except UserAlreadyInRoom:
            logging.warning("Cannot add user %s to room %s, already in room" % (user.username, room.name))
            self.render_page(template_values, { "user_already_in_room": True })
            return
        
        # Saving room to database.
        room.put()
        
        redirect_url = webapp2.uri_for("chat") + "?" + urllib.urlencode({
            ROOM_URL_ARGUMENT: room_name,
            USER_URL_ARGUMENT: username
        })            
        self.redirect(redirect_url)
    
    def render_page(self, values={}, errors={}):
        """Page with a login form with given values and errors displayed."""
        
        active_rooms = [room for room in Room.all().filter("expired", False).run()]
        available_rooms = [room for room in active_rooms if not room.is_full()]
        
        template_values = {
            "available_rooms"      : available_rooms,
            "form_action_url"      : webapp2.uri_for("login"),
            "register_url"         : webapp2.uri_for("register"),
            "password_recovery_url": webapp2.uri_for("password_recovery"),
            "values"               : values,
            "errors"               : errors,
            "room_limits"          : ROOM_LIMITS,
            "user_limits"          : USER_LIMITS
        }
        template_path = os.path.join(
            os.path.dirname(__file__),
            '../templates/login.html'
        )
        self.response.out.write(template.render(template_path, template_values))